package top.archiesean.handler;


import com.alibaba.fastjson.JSON;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.springframework.beans.BeansException;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import top.archiesean.annotation.RpcService;
import top.archiesean.common.RpcRequest;
import top.archiesean.common.RpcResponse;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 1. 将标有@rpcService注解的bean缓存
 * 2. 接收客户端请求
 * 3. 根据传递过来的beanName，从换从中查找bean
 * 4. 解析请求中的方法名称、参数类型、参数信息
 * 5. 反射调用
 * 6. 给客户端响应
 *
 * @author ArchieSean
 * @description 服务端业务处理类
 * @date 2024-03-06
 */
@Component
@ChannelHandler.Sharable
public class RpcServerHandler extends SimpleChannelInboundHandler<String> implements ApplicationContextAware {


    private static final Map<String, Object> SERVICE_INSTANCE_MAP = new HashMap<>();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        //1. 接收消息
        RpcRequest rpcRequest = JSON.parseObject(msg.toString(), RpcRequest.class);

        RpcResponse response = new RpcResponse();
        response.setRequestId(rpcRequest.getRequestId());
        try {
            Object result = handler(rpcRequest);
            response.setResult(result);
        } catch (Exception ex) {
            response.setError(ex.getLocalizedMessage());
        }

        //响应
        ctx.writeAndFlush(JSON.toJSONString(response));
    }

    /**
     * 业务处理
     *
     * @return obj
     */
    public Object handler(RpcRequest request) throws InvocationTargetException {
        String className = request.getClassName();
        if (!SERVICE_INSTANCE_MAP.containsKey(className)) {
            throw new RuntimeException("目标服务不存在");
        }
        Object serviceBean = SERVICE_INSTANCE_MAP.get(className);
        Class<?> targetClass = serviceBean.getClass();

        //获取本地请求方法名称
        String methodName = request.getMethodName();

        //获取参数类型
        Class<?>[] parameterTypes = request.getParameterTypes();

        //获取具体参数
        Object[] parameters = request.getParameters();

        //此处使用cglib去反射调用
        FastClass fastClass = FastClass.create(targetClass);
        FastMethod method = fastClass.getMethod(methodName, parameterTypes);
        return method.invoke(serviceBean, parameters);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RpcService.class);

        if (CollectionUtils.isEmpty(beansWithAnnotation)) {
            return;
        }
        for (Map.Entry<String, Object> item : beansWithAnnotation.entrySet()) {
            Object serviceBean = item.getValue();
            Class<?>[] interfaces = serviceBean.getClass().getInterfaces();
            if (interfaces.length == 0) {
                throw new RuntimeException("服务必须实现接口");
            }
            //默认取第一个接口作为缓存key
            String cacheKey = Arrays.stream(interfaces).findFirst().get().getName();

            SERVICE_INSTANCE_MAP.put(cacheKey, serviceBean);
        }
    }
}
